package com.zhixing.gateway.filters;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.zhixing.common.config.ExcludePathsProperties;
import com.zhixing.common.constant.Constant;
import com.zhixing.common.domain.enums.HttpStatus;
import com.zhixing.common.domain.entity.UserInfo;
import com.zhixing.common.utils.JwtUtil;
import com.zhixing.common.utils.Res;
import io.jsonwebtoken.JwtException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static com.alibaba.fastjson2.JSONWriter.Feature.WriteMapNullValue;
import static com.zhixing.common.constant.Constant.*;

@Slf4j
@Component
@RequiredArgsConstructor
public class TokenGlobalFilter implements GlobalFilter, Ordered {

    private final ExcludePathsProperties excludePathsProperties;
    private final StringRedisTemplate stringRedisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 路由白名单放行
        ServerHttpRequest request = exchange.getRequest();
        if (excludePathsProperties.getExcludePaths().stream().anyMatch(request.getPath().toString()::startsWith)) {
            return chain.filter(exchange);
        }

        // 校验token
        List<String> headers = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
        String token = null;
        if (CollUtil.isNotEmpty(headers)) token = headers.get(0);
        UserInfo userInfo;
        try {
            userInfo = JwtUtil.parseToken(token);
            String key = ZHIXING_USER_TOKEN + userInfo.getId();
            Long expire = stringRedisTemplate.getExpire(key);
            if (ObjectUtil.isEmpty(expire) || expire <= 0) throw new JwtException("token已失效");
            else if (expire < ONE_DAY_SECOND) stringRedisTemplate.expire(key, WEEK, TimeUnit.DAYS);
        } catch (JwtException e) {
            log.info("token校验失败：{}", e.getMessage());
            ServerHttpResponse response = exchange.getResponse();
            response.getHeaders().add("Content-Type", "application/json");
            Res<?> res = Res.error(HttpStatus.UNAUTHORIZED.getCode(), e.getMessage());
            byte[] bytes = JSON.toJSONString(res, WriteMapNullValue).getBytes();
            DataBuffer dataBuffer = response.bufferFactory().wrap(bytes);
            return response.writeWith(Mono.just(dataBuffer));
        }

        // 传递用户信息
        ServerWebExchange mutateExchange = exchange.mutate()
                .request(builder -> builder.header(Constant.USER_INFO, JSON.toJSONString(userInfo)))
                .build();
        return chain.filter(mutateExchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
